#include <53func.h>
// v 1.0
//int recvFile(int sockfd){
//    char filename[4096] = {0};
//    recv(sockfd,filename,sizeof(filename),0);
//    int fd = open(filename,O_RDWR|O_CREAT,0666);
//    char buf[4096] = {0};
//    ssize_t sret = recv(sockfd,buf,sizeof(buf),0);
//    write(fd,buf,sret);
//    return 0;
//}
// v 2.0
typedef struct train_s {
    int length;
    char data[1000];
} train_t;
//int recvFile(int sockfd){
//    train_t train;
//    recv(sockfd,&train.length,sizeof(int),0);
//    recv(sockfd,train.data,train.length,0);
//
//    char filename[4096] = {0};
//    memcpy(filename,train.data,train.length);
//    int fd = open(filename,O_RDWR|O_CREAT,0666);
//    
//    recv(sockfd,&train.length,sizeof(int),0);
//    recv(sockfd,train.data,train.length,0);
//    write(fd,train.data,train.length);
//    return 0;
//}
// v 3.0
//int recvFile(int sockfd){
//    train_t train;
//    recv(sockfd,&train.length,sizeof(int),MSG_WAITALL);
//    recv(sockfd,train.data,train.length,MSG_WAITALL);
//
//    char filename[4096] = {0};
//    memcpy(filename,train.data,train.length);
//    int fd = open(filename,O_RDWR|O_CREAT,0666);
//    
//    while(1){
//        recv(sockfd,&train.length,sizeof(int),MSG_WAITALL);
//        if(train.length != 1000){
//            printf("train.length = %d\n", train.length);
//        }
//        if(train.length == 0){
//            break;
//        }
//        recv(sockfd,train.data,train.length,MSG_WAITALL);
//        write(fd,train.data,train.length);
//    }
//    return 0;
//}
// v 3.1 recvn
int recvn(int sockfd, void *buf, int n){
    int total = 0;
    char *p = (char *)buf;
    while(total < n){
        ssize_t sret = recv(sockfd,p+total,n-total,0);
        total += sret;
    }
    return 0;
}
//int recvFile(int sockfd){
//    train_t train;
//    recvn(sockfd,&train.length,sizeof(int));
//    recvn(sockfd,train.data,train.length);
//    char filename[4096] = {0};
//    memcpy(filename,train.data,train.length);
//    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    
//    while(1){
//        recvn(sockfd,&train.length,sizeof(int));
//        if(train.length != 1000){
//            printf("train.length = %d\n", train.length);
//        }
//        if(train.length == 0){
//            break;
//        }
//        recvn(sockfd,train.data,train.length);
//        write(fd,train.data,train.length);
//    }
//    return 0;
//}
// v 4.0
//int recvFile(int sockfd){
//    train_t train;
//    recvn(sockfd,&train.length,sizeof(int));
//    recvn(sockfd,train.data,train.length);
//    char filename[4096] = {0};
//    memcpy(filename,train.data,train.length);
//    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    
//    recvn(sockfd,&train.length,sizeof(int));
//    recvn(sockfd,train.data,train.length);
//    off_t filesize;
//    memcpy(&filesize,train.data,sizeof(off_t));
//    printf("filesize = %ld\n", filesize);
//    off_t cursize = 0;
//    off_t lastsize = 0;
//    off_t slice = filesize/10000;
//    while(1){
//        recvn(sockfd,&train.length,sizeof(int));
//        if(train.length != 1000){
//            printf("train.length = %d\n", train.length);
//        }
//        if(train.length == 0){
//            break;
//        }
//        cursize += train.length;
//        if(cursize - lastsize > slice){
//            printf("%5.2lf%%\r",100.0*cursize/filesize);
//            fflush(stdout);
//            lastsize = cursize;
//        }
//        recvn(sockfd,train.data,train.length);
//        write(fd,train.data,train.length);
//    }
//    printf("100.00%%\n");
//    return 0;
//}
//v 5.0
int recvFile(int sockfd){
    train_t train;
    recvn(sockfd,&train.length,sizeof(int));
    recvn(sockfd,train.data,train.length);
    char filename[4096] = {0};
    memcpy(filename,train.data,train.length);
    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
    
    recvn(sockfd,&train.length,sizeof(int));
    recvn(sockfd,train.data,train.length);
    off_t filesize;
    memcpy(&filesize,train.data,sizeof(off_t));
    printf("filesize = %ld\n", filesize);

    ftruncate(fd,filesize);
    char *p = (char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,
                           fd,0);
    recvn(sockfd,p,filesize);
    munmap(p,filesize);
    close(fd);
    return 0;
}
int main(int argc, char *argv[])
{
    // ./3_azhen_select 192.168.38.128 1234
    ARGS_CHECK(argc,3);
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET; // AF_INET ipv4
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    // 赋值用具体类型 传参时强转成公共类型
    int ret = connect(sockfd,(struct sockaddr *)&addr, sizeof(addr));
    // connect 填的是服务端地址
    ERROR_CHECK(ret,-1,"connect");
    recvFile(sockfd);
    close(sockfd);
    return 0;
}

